﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace P
{

    //一、什么是原型模式？
    //原型模式是一种创建型设计模式，它的核心思想是：
    //通过复制（或克隆）一个已经存在的对象来创建新的对象，而不是通过new来实例化出来一个新对象。

    //二、适用场景

    //1.创建对象的成本很高（比如需要大量计算、数据库查询、远程服务调用等）。
    //2.希望在运行时动态创建对象，而不是依赖类的构造器实例化出来一个。
    //3.对象的种类非常多，且需要根据已有对象快速复制。
    //4.需要创建的对象结构复杂且需要部分修改。

    //相关案例
    //以一个“简历对象”为例，我们希望快速复制一份已有简历，然后稍微修改部分内容（比如应聘职位)。

    //    五、原型模式的优缺点
    //✅ 优点
    //性能提升：通过复制已有对象，避免重复创建代价大的对象。
    //动态复制：无需依赖类的构造函数，可以在运行时复制对象。
    //结构灵活：克隆出的对象可以独立修改，不影响原始对象。

    //❌ 缺点
    //对象克隆复杂：尤其是当对象中包含引用类型（集合、嵌套对象等），要考虑深拷贝和浅拷贝。
    //维护成本高：当对象结构复杂或经常变化时，手写拷贝构造函数可能繁琐


    //六、原型模式 vs 其它创建型模式
    // 模式             核心思想          对象创建方式
    //工厂方法      延迟创建逻辑到派生类   通过派生类 new 出来
    //抽象工厂      创建一系列相关对象     通过多个工厂方法
    //建造者模式    分步骤构建复杂对象     调用一系列构建方法
    //原型模式      克隆现有对象          调用.Clone()

    //七、实际应用场景
    //场景                            示例
    //游戏开发              复制怪物、角色、装备（修改某些参数）
    //Revit/CAD开发         复制已有元素（图元）并稍作调整
    //表单生成              快速复制并定制控件组
    //数据缓存              快速从模板对象复制一份作为初始状态
    //WPF控件复制           克隆已有控件，保持绑定结构不变


    class Person
    {
        public string Name;
        public Address Addr;
    }

    class Address
    {
        public string City;
    }

    class Person2
    {
        public string Name;     //行为特殊, 本质上是引用类型
        public Address Addr;    //引用类型

        /// <summary>
        /// 自己写深拷贝方法
        /// </summary>
        /// <returns></returns>
        public Person2 DeepCopy()
        {
            return new Person2
            {
                Name = this.Name,
                Addr = new Address { City = this.Addr.City }

                //Addr = this.Addr,
            };
        }
    }



    /// <summary>
    /// 复制原型
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            //func1();

            //func2();


            //func3();

            //func4();

            //func5();

            //func6();

            func7();

            Console.ReadKey();
        }

        static void func1()
        {
            Client client = new Client();
            IPrototype prototype = client.CloneA();
            Console.WriteLine(prototype);
        }

        static void func2()
        {
            Client client = new Client();
            IPrototype prototype = client.CloneB();
            Console.WriteLine(prototype);
        }



        /// <summary>
        /// 深拷贝案例
        /// </summary>
        static void func3()
        {
            var p1 = new Person { Name = "Tom", Addr = new Address { City = "Tokyo" } };
            var p2 = p1;  //引用复制

            p2.Name = "Jerry";
            p2.Addr.City = "shanghai";

            Console.WriteLine(p1.Name);        // Jerry ✅ 复制的是值
            Console.WriteLine(p1.Addr.City);   // Osaka ❌ 地址是共享的

            Console.WriteLine(p2.Name);        // Jerry ✅ 复制的是值
            Console.WriteLine(p2.Addr.City);   // Osaka ❌ 地址是共享的
        }



        /// <summary>
        /// 浅拷贝案例
        /// </summary>
        static void func4()
        {
            var p1 = new Person2 { Name = "张三", Addr = new Address { City = "Tokyo" } };
            var p2 = p1;  //引用复制

            p2.Name = "李四";
            p2.Addr.City = "Shanghai";

            Console.WriteLine(p1.Name);        // Jerry ✅ 复制的是值
            Console.WriteLine(p1.Addr.City);   // Osaka ❌ 地址是共享的

            Console.WriteLine(p2.Name);        // Jerry ✅ 复制的是值
            Console.WriteLine(p2.Addr.City);   // Osaka ❌ 地址是共享的
        }


        /// <summary>
        /// 深拷贝案例
        /// </summary>
        static void func5()
        {
            var p1 = new Person2 { Name = "Tom", Addr = new Address { City = "Tokyo" } };
            var p2 = p1.DeepCopy();  //深拷贝

            p2.Name = "Jerry";
            p2.Addr.City = "shanghai";

            Console.WriteLine(p1.Name);        // Jerry ✅ 复制的是值
            Console.WriteLine(p1.Addr.City);   // Osaka ❌ 地址是共享的

            Console.WriteLine(p2.Name);        // Jerry ✅ 复制的是值
            Console.WriteLine(p2.Addr.City);   // Osaka ❌ 地址是共享的
        }


        /// <summary>
        /// 值类型实例
        /// </summary>
        static void func6()
        {
            int a = 10;
            int b = a;   // 复制了 a 的值

            b = 20;

            Console.WriteLine(a); // 10 ✅ 原值未变
            Console.WriteLine(b); // 20
        }


        static void func7()
        {
            Person p1 = new Person { Name = "Tom" };
            var p2 = p1;  // 复制引用

            p2.Name = "Jerry";   //修改

            Console.WriteLine(p1.Name); // Jerry ❗共享引用
            Console.WriteLine(p2.Name); //
        }


    }
}
